#include "CH58x_common.h"
#include "zqm_global.h"
#include "zqm_module.h"
#include "hal_mcu.h"
#include "hal_uart.h"
#include "task_ota.h"
#include "task_c485.h"
#include "task_gather.h"
#include "task_console.h"
#include "stdlib.h"
#include "share.h"

#ifdef _WIN32
#pragma warning(disable:4098)
#endif

#define C485_RX_BUF_SIZE    2080    // 2048 + 32
static uint8_t c485_rx_buf[C485_RX_BUF_SIZE];
static uint16_t c485_not_response_timer = 0;    // 这个值大于0用于某些反向命令时，通知已经是上位机的回复，系统不需要再回复回复

// 485通信协议数据类型定义
typedef enum {
    C485_DT_BYTE = 1,
    C485_DT_SHORT,
    C485_DT_INT,
    C485_DT_STR,    
    C485_DT_NUM,    
} C485DataType;
// 485通信协议单个数据长度定义
const uint8_t C485_data_type_size_tb[C485_DT_NUM] = {0, 1, 2, 4, 1};
// C485对系统各种参数的追踪，以便发现参数更新
typedef struct {
    uint8_t run_state;          // 运行状态
    uint16_t fault_code;        // 故障代码
    uint8_t comp_status;        // 压机状态
    uint8_t door_state;         // 门状态
    uint8_t light_state;        // 灯状态
    uint8_t pow_timer;          // 功率参数上报计时
    uint8_t net_flag;           // 网络状态初始化查询标志
    uint8_t fan_status;         // 蒸发风机状态
    uint8_t light_cur_timer;    // 灯电流上报计时
    uint8_t _4g_strength_flag;  // 4g信号强度初始化查询标志
    uint8_t ctrl_mode;          // 控制器制冷/制热状态
    short pm_ts;                // 设置温度
    short pm_f5;                // 高温报警温度    
    short pm_f6;                // 低温报警温度    
    short pm_r1;                // 设置温度下限    
    short pm_r2;                // 设置温度上限    
    short pm_c1;                // 设置温度上回差
    short pm_c2;                // 设置温度下回差
    short pm_c5;                // 设置温度补偿值
    uint8_t local_switch;       // 本地开关状态
} C485DataRecord;               // C485历史数据记录结构, 用来追踪系统状态的变化
static C485DataRecord c485_data_record = {0x7f};   // C485历史数据记录, 用来追踪系统状态的变化
static uint8_t c485_run_state = 0x00;           // C485视角下的系统运行状态

// 追踪参数的变化, 加入report非空, 有变化会调用report上报
// return: 0 - 无变化或没有成功记录变化, 1 - 成功记录变化
bool sync_param_short(short sys, short *trace, bool (*report)(short value))
{
    if (sys == *trace) return 0; // 无变化
    if (report) {    // 需要上报
        if (report(sys)) return (*trace = sys); // 上报且发出成功
        else return 0; // 上报但发出失败
    }
    else return (*trace = sys);   // 不需要上报仅记录
}
bool sync_param_byte(uint8_t sys, uint8_t *trace, bool (*report)(uint8_t value))
{
    if (sys == *trace) return 0; // 无变化
    if (report) {    // 需要上报
        if (report(sys)) return (*trace = sys); // 上报且发出成功
        else return 0; // 上报但发出失败
    }
    else return (*trace = sys);   // 不需要上报仅记录
}

//  485通信协议打包函数 -----------------------------------------------------------------------------------------------
// init package buffer
int C485PkgBegin(C485PkgHandle *pkg, uint16_t cmd, uint8_t *buf, uint16_t size, uint8_t ordinal)
{
    if(size < 14) return -1;    // 已知最小指令长度14, 指令头(0xdd)+长度(2B)+机器号(0x02)+指令(2B)+报文序号(1B)+报文块数(1B)+报文类型(1B)+数据个数(2B)+数据(1B)+校验和(1B)+指令尾(1B)
    pkg->buf = buf; 
    pkg->size = size;
    pkg->pos = 0;

    C485PkgHead *head = (C485PkgHead *)buf;
    head->flag = 0xdd;              // 指令头(0xdd)
    head->len = 0;                  // 长度(2B)
    head->machine_num = 0x02;       // 机器号(0x02)
    head->cmd = ZQ_SWAP_WORD(cmd);  // 指令(0x02)
    head->ordinal = ordinal;        // 报文序号(1B)
    head->block_num = 0;            // 报文块数(1B)
    return 0;
}
// set the ordinal number
int C485PkgSetOrdinal(C485PkgHandle *pkg, uint8_t num)
{
    C485PkgHead *head = (C485PkgHead *)pkg->buf;
    head->ordinal = num;
    return 0;
}
// add a new data block
int C485PkgAddBlock(C485PkgHandle *pkg)
{
    C485PkgHead *head = (C485PkgHead *)pkg->buf;
    head->block_num++;
    if(pkg->pos == 0) // 初始化打包位置到第一个block起始点
        pkg->pos = sizeof(C485PkgHead);
    return 0;
}
int C485PkgAddData(C485PkgHandle *pkg, uint8_t *data, uint16_t num, C485DataType type)
{
    uint8_t d_len = C485_data_type_size_tb[type];
    if((pkg->pos + 1 + 2 + d_len * num) > (pkg->size - 2)) return -1; // 预计打包长度溢出
    uint8_t *p = pkg->buf + pkg->pos;
    *p++ = type;                                        // 报文类型(1B)
    *p++ = (uint8_t)(num >> 8);                         // 数据个数(2B)
    *p++ = (uint8_t)num;
    for(uint16_t i = 0; i < num; i++, data += d_len) {  // 数据, big endian
        for(uint8_t j = 1; j <= d_len; j++)
            *p++ = data[d_len - j];
    }
    pkg->pos = p - pkg->buf;
    return 0;
}
int C485PkgEnd(C485PkgHandle *pkg)
{
    uint8_t *p = pkg->buf + pkg->pos;
    C485PkgHead* head = (C485PkgHead*)pkg->buf;
    head->len = ZQ_SWAP_WORD(pkg->pos - 3);
    p[0] = ZqGetChecksum(pkg->buf+1, pkg->pos-1);
    p[1] = 0x88;
    pkg->pos += 2;
    return 0;
}

// 485通信协议UART发送接收函数 -----------------------------------------------------------------------------------------------
#define C485_def_buf_len 64
static uint8_t C485_def_buf[C485_def_buf_len];              // 大部分指令小于64字节, 使用这个共享buf减少内存分配次数, 
static uint8_t C485_def_retry_buf[C485_def_buf_len];        // 大部分需要重试的指令小于64字节, 使用这个共享buf减少内存分配次数
uint8_t *C485_resend_buf = NULL;                            // 记录需要重试发送的数据
uint16_t C485_resend_len = 0;                               // 记录需要重试发送的数据长度
uint16_t C485_resend_timer = 5000;                          // 记录需要重试发送的数据的倒计时
// 立刻从串口C485_UART_PORT发送数据
void C485SendData(uint8_t *data, uint16_t len)
{
    UartSend(C485_UART_PORT, data, len);     // send with uart1 directly
}
// 记录下要发送的数据，从下一个任务循环(TASK_PERIOD后)开始发送
bool C485SendDataWithRetry(uint8_t *data, uint16_t len)
{
    if(C485_resend_buf != NULL) return false; // last send task has not completed.
    // copy 
    if(len <= C485_def_buf_len)  // 数据小于C485_def_buf_len, 使用预先分配的共享buf
        C485_resend_buf = C485_def_retry_buf;
    else
        C485_resend_buf = malloc(len);
    if(C485_resend_buf == NULL) return false;
    memcpy(C485_resend_buf, data, len);
    C485_resend_len = len;
    C485_resend_timer = 5000;
    return true;
}
// every TASK_PERIOD will be called. 
void C485ResendData()
{
    if(C485_resend_buf == NULL) return; // no data
    if(C485_resend_timer == 0) { // overtime, clear data
        if(C485_resend_len > C485_def_buf_len) free(C485_resend_buf); // 数据大于C485_def_buf_len, 使用客户分配的buf, 要释放
        C485_resend_buf = NULL;
        return;
    }
    // 倒计时从5s开始, 每隔1s尝试发送一次, 共3次, 5s超时, 考虑到会和下发命令连续撞车, 后两次提前50ms开始
    if(C485_resend_timer == 5000 || C485_resend_timer == 4050 || C485_resend_timer == 3050) {
        // 本485是单工, 所以一旦接收buffer里有数据, 说明在接收中, 要避让(本次暂停倒计时)
        if(zq_uart_handle[C485_UART_PORT].rx_buf_pos > 0) return;
        C485SendData(C485_resend_buf, C485_resend_len);
    }
    C485_resend_timer -= TASK_PERIOD;
}
// 每TASK_PERIOD轮询接收buffer, 处理上位机指令
void C485Recv(void (*rx_cb)(C485PkgHead* head))
{
#if (!ZQ_SIMULATOR)
    ZqUartHandle *puh = zq_uart_handle + C485_UART_PORT;
#else
    ZqSimuUartHandle *puh = zq_simu_uart_handle + C485_UART_PORT;
#endif
    uint8_t* data = puh->rx_buf;
    uint16_t buf_size = puh->rx_buf_size;
    uint16_t data_len = puh->rx_buf_pos;
    uint16_t step = 0;
    C485PkgHead *head;
    
    static uint16_t left = 0;   // 记录上次处理剩下的数据(没满足一个pkg)
    if(left != 0 && left == data_len) { // 经过一个loop, 未成包的数据长度没有变化, 也就是50ms没有收到新数据, 认为超时, 及时清除. 不然对于单工的485来说, 本APP机制会阻塞发送.
        UartLock(C485_UART_PORT);    // 锁定(582上是关闭相应中断)
        puh->rx_buf_pos = 0;
        UartUnlock(C485_UART_PORT);    // 解锁(582上是打开相应中断)
        return;
    }
        
    extern int UartIfSwitchToFtm(uint8_t *data, uint16_t data_len);
    if(UartIfSwitchToFtm(data, data_len) == 1) return;        // 特别FTM切换命令

    for (; step < data_len; step += head->len) {
        left = data_len - step;
        if (left < 14) return; // 已知最小指令长度14, 指令头(0xdd)+长度(2B)+机器号(0x02)+指令(2B)+报文序号(1B)+报文块数(1B)+报文类型(1B)+数据个数(2B)+数据(1B)+校验和(1B)+指令尾(1B)
        head = (C485PkgHead *)(data + step);
        uint16_t len = ZQ_SWAP_WORD(head->len) + 5;     // 总长度
        if (head->flag != 0xdd || len > buf_size || len < 14) {// 标志出错或长度出错, discard all data
            step = 0xffff;
            break;
        }
        if (len > left) return; // wait more data
        if (ZqGetChecksum(data+1, len-2) != 0) { // checksum error
            step = 0xffff;
            break;
        }
        head->len = ZQ_SWAP_WORD(head->len);
        head->cmd = ZQ_SWAP_WORD(head->cmd);

        // 处理上位机的指令数据
        rx_cb(head);
    }

    if (step > 0) { // there are discard data, need to djust the data pointer of receive buffer
        UartLock(C485_UART_PORT);    // 锁定(582上是关闭相应中断)
        if (step == 0xffff) { // 数据异常, clear receive buffer
            puh->rx_buf_pos = left = 0;
        }
        else {
            puh->rx_buf_pos -= step;
            memcpy(data, data + step, puh->rx_buf_pos);
        }
        UartUnlock(C485_UART_PORT);    // 解锁(582上是打开相应中断)
    }
}

// 485通信协议应答发送函数 -----------------------------------------------------------------------------------------------
// 发送应答数据相对简单, 打包发送即可, 没有重试机制
int C485SendResponseFewData(uint16_t cmd, uint8_t* data, uint16_t data_num, C485DataType data_type, uint8_t ordinal)
{
    C485PkgHandle pkg;
    // pack
    C485PkgBegin(&pkg, cmd, C485_def_buf, C485_def_buf_len, ordinal);
    C485PkgAddBlock(&pkg);
    C485PkgAddData(&pkg, data, data_num, data_type);
    C485PkgEnd(&pkg);
    // send
    C485SendData(pkg.buf, pkg.pos);
    return 0;
}
// 发送指令数据, 打包后发送，有重试机制
bool C485SendCmdFewData(uint16_t cmd, uint8_t* data, uint16_t data_num, C485DataType data_type, uint8_t ordinal)
{
    C485PkgHandle pkg;
    // pack
    C485PkgBegin(&pkg, cmd, C485_def_buf, C485_def_buf_len, ordinal);
    C485PkgAddBlock(&pkg);
    C485PkgAddData(&pkg, data, data_num, data_type);
    C485PkgEnd(&pkg);
    // send
    return C485SendDataWithRetry(pkg.buf, pkg.pos);
}
// 继续包装发送单个byte, short, int, string, 方便使用
void C485SendResponseByte(uint16_t cmd, uint8_t data, uint8_t ordinal)
{
    C485SendResponseFewData(cmd, &data, 1, C485_DT_BYTE, ordinal);
}
void C485SendResponseShort(uint16_t cmd, short data, uint8_t ordinal)
{
    //data = ZQ_SWAP_WORD(data);
    C485SendResponseFewData(cmd, (uint8_t *)&data, 1, C485_DT_SHORT, ordinal);
}
void C485SendResponseInt(uint16_t cmd, int data, uint8_t ordinal)
{
    //data = ZQ_SWAP_DWORD(data);
    C485SendResponseFewData(cmd, (uint8_t *)&data, 1, C485_DT_INT, ordinal);
}
void C485SendResponseStr(uint16_t cmd, char *data, uint8_t ordinal)
{
    C485SendResponseFewData(cmd, (uint8_t *)data, strlen(data), C485_DT_STR, ordinal);
}
bool C485SendCmdByte(uint16_t cmd, uint8_t data)
{
    return C485SendCmdFewData(cmd, &data, 1, C485_DT_BYTE, 1);
}


// 各种具体指令处理 -----------------------------------------------------------------------------------------------
// Cmd0101, 通信监测
static void C485Cmd0101Resp(C485PkgHead *head)
{
    c485_run_state = C485_RUN_STATE_CONNECTED;
    // 冰柜电子温控器将接收到的指令直接返回
    C485SendResponseByte(0x0101, head->data[3], head->ordinal);
}
// Cmd0102, 无效指令应答, 特殊指令, 只有下位机发出, 无需应答, 电子温控器不支持智能模块发送的指令时返回该指令
static void C485Cmd0102Resp(C485PkgHead *head)
{
    // 温控器不支持智能模块发送的指令
    //short data = ZQ_SWAP_WORD(head->cmd);
    //C485SendResponseShort(0x0102, data, head->ordinal);
    C485SendResponseShort(0x0102, head->cmd, head->ordinal);
}
// Cmd0103, 自动发送指令应答, 特殊指令, 只有上位机发出, 无需应答, 智能模块接收了冰柜电子温控器自动发送的指令时进行应答
static void C485Cmd0103Resp(C485PkgHead *head)
{
    // 温控器收到智能模块应答, 清除重发机制, 无需回应
    if(C485_resend_buf == NULL) return;     // 温控器没有需要应答的数据
    C485PkgHead *pkg_send = (C485PkgHead *)C485_resend_buf;
    uint16_t cmd = (head->data[3] << 8) | head->data[4];
    if(ZQ_SWAP_WORD(pkg_send->cmd) == cmd) {// receive correct response, clear retry data.
        if(C485_resend_len > C485_def_buf_len) free(C485_resend_buf); // 数据大于C485_def_buf_len, 使用客户分配的buf, 要释放
        C485_resend_buf = NULL; 
    }
}
// Cmd0111, 设备重启
static void C485Cmd0111Resp(C485PkgHead *head)
{
    //zy_st.ctrl_state = CTRL_STATE_RESET_HD;
    //// 冰柜电子温控器判断可以进行重启则返回成功，否则返回失败
    //C485SendResponseByte(0x0111, 1, head->ordinal);
    
    // 协议修改：不支持远程重启命令
    return C485Cmd0102Resp(head);    // 不支持
}
static uint8_t ota_oridinal = 0;
static int ota_image_size = 0;
// Cmd0112, 程序升级开始
static void C485Cmd0112Resp(C485PkgHead *head)
{
    // TODO 缺少OTA image len
    // 1. 记录image len
    ota_image_size = ((int)head->data[3] << 24) | ((int)head->data[4] << 16) | ((int)head->data[5] << 8) | head->data[6];
    if(ota_image_size > IMAGE_SIZE) return; // 数据大于C485_OTA_MAX_SIZE
    // 2. clear 
    ota_oridinal = 0;
    // 3. 设置进入OTA状态
    c485_run_state = C485_RUN_STATE_OTA;
    // 4. 启动OTA
    OtaBegin(ota_image_size);
    // 冰柜电子温控器判断可以进行重启则返回成功，否则返回失败
    C485SendResponseByte(0x0112, 1, head->ordinal);
}
// Cmd0113, 程序升级传送 -- TODO must aligned to 4 bytes.
static void C485Cmd0113Resp(C485PkgHead *head)
{
    if(c485_run_state != C485_RUN_STATE_OTA)
        C485SendResponseByte(0x0113, 0, head->ordinal);
    if((head->ordinal - ota_oridinal) != 1)
        C485SendResponseByte(0x0113, 0, head->ordinal);
    ota_oridinal++;
    short size = ((short)head->data[1] << 8) | head->data[2];
    OtaRecvData(head->data + 3, size);
    // 冰柜电子温控器判断可以进行重启则返回成功，否则返回失败
    C485SendResponseByte(0x0113, 1, head->ordinal);
}
// Cmd0114, 程序版本取得
static void C485Cmd0114Resp(C485PkgHead *head)
{
    char version_str[16] = {0};
    strcpy(version_str, ZQ_SW_VER_STR);
    version_str[strlen(version_str)-3] = 0;
    C485SendResponseStr(0x0114, version_str, head->ordinal);
}
// Cmd0115, 硬件版本取得
static void C485Cmd0115Resp(C485PkgHead *head)
{
    char version_str[16] = {0};
    strcpy(version_str, ZQ_HW_VER_STR);
    version_str[strlen(version_str)-3] = 0;
    C485SendResponseStr(0x0115, version_str, head->ordinal);
}
// Cmd0116, 厂家代码取得
static void C485Cmd0116Resp(C485PkgHead *head)
{
#if((CFG_DEVICE_TYPE/100) == 24326) // 自研机型无此参数
    C485Cmd0102Resp(head);    // 不支持
#else
    C485SendResponseStr(0x0116, CFG_MANUFACTURE_CODE, head->ordinal);
#endif
}

// Cmd0121, 设备类型取得
static void C485Cmd0121Resp(C485PkgHead *head)
{
#if((CFG_DEVICE_TYPE/100) == 24326) // 自研机型无此参数
    C485Cmd0102Resp(head);    // 不支持
#else
    uint8_t type = (uint8_t)atoi(AKM_DEV_TYPE);
    C485SendResponseByte(0x0121, type, head->ordinal);
#endif
}
// Cmd0122, 设备功能取得
// #define FUN_GPS_NUM		            0x0001
// #define FUN_WIFI_NUM	                0x0002
// #define FUN_BT_NUM		            0x0004
// #define FUN_TCM_NUM		            0x0008
// #define FUN_COMPRESS_NUM             0x0010
// #define FUN_DOORSW_NUM	            0x0020
// #define FUN_BATTERY_NUM	            0x0040
// #define FUN_TEMPCTRL_NUM             0x0080
// #define FUN_POWERCHK_NUM             0x0100
// #define FUN_FANCTRL_NUM	            0x0200
// #define FUN_HUMMANCHK_NUM            0x0400
// #define FUN_GRAPHCHK_NUM             0x0800
// #define FUN_POWERSAVE_NUM            0x1000
// #define FUN_LIGHTCTRL_NUM            0x2000
// #define FUN_LIGHTCURRENTCHK_NUM      0x4000
// #define FUN_SURROUDTENPCHK_NUM       0x8000

static void C485Cmd0122Resp(C485PkgHead *head)
{
#if((CFG_DEVICE_TYPE/100) == 24326) // 自研机型无此参数
    return C485Cmd0102Resp(head);    // 不支持
#endif
    uint16_t func_num = 0;
    // char funcs[64];
    // strncpy(funcs, AKM_CTRL_FUNC, 64);
    // funcs[63] = 0;
    // char* token;
    // // 使用逗号作为分隔符进行分割
    // token = strtok(funcs, ",");
    // while (token != NULL) {
    //     uint16_t x = (uint16_t)atoi(token);
    //     if(x == 13) func_num |= 0;
    //     else if(x == 14) func_num |= 0x2000;
    //     else if(x == 15) func_num |= 0x4000;
    //     else if(x == 16) func_num |= 0x8000;
    //     else if(x == 17) func_num |= 0x0;
    //     else if(x == 18) func_num |= 0x0;
    //     else if(x == 19) func_num |= 0x1000;
    //     else if(x == 20) func_num |= 0x0;
    //     else if(x == 21) func_num |= 0x0;
    //     else if(x == 22) func_num |= 0x0;
    //     else if(x == 23) func_num |= 0x0;
    //     else if(x == 24) func_num |= 0x0;
    //     else func_num |= (1 << (x - 1));
    //     token = strtok(NULL, ",");  // 继续分割下一个子串
    // }
    for(int x = 1; x < 32; x++) {
        if((AKM_CTRL_FUNC & (1<<x)) == 0) continue;
        if(x == 13) func_num |= 0;
        else if(x == 14) func_num |= 0x2000;
        else if(x == 15) func_num |= 0x4000;
        else if(x == 16) func_num |= 0x8000;
        else if(x == 17) func_num |= 0x0;
        else if(x == 18) func_num |= 0x0;
        else if(x == 19) func_num |= 0x1000;
        else if(x == 20) func_num |= 0x0;
        else if(x == 21) func_num |= 0x0;
        else if(x == 22) func_num |= 0x0;
        else if(x == 23) func_num |= 0x0;
        else if(x == 24) func_num |= 0x0;
        else func_num |= (1 << (x - 1));
    }
    C485SendResponseShort(0x0122, (short)func_num, head->ordinal);
}
// Cmd0123, 系统时间设定
static void C485Cmd0123Resp(C485PkgHead *head)
{
    return C485Cmd0102Resp(head);    // 不支持
}
// Cmd0124, 系统时间取得
static void C485Cmd0124Resp(C485PkgHead *head)
{
    return C485Cmd0102Resp(head);    // 不支持
}
// Cmd0125, 运行状态取得
static void C485Cmd0125Resp(C485PkgHead* head)
{
    //C485SendResponseByte(0x0125, c485_data_record.run_state, head->ordinal);
    uint8_t state = c485_run_state;
    if (state == C485_RUN_STATE_CONNECTED) 
        state = C485_RUN_STATE_NORMAL;
    C485SendResponseByte(0x0125, state, head->ordinal);
}
// Cmd0125, 运行状态取得 - 主动
static bool C485Cmd0125(uint8_t value)
{
    // 协议更新，不支持
    //C485SendCmdByte(0x0125, value);
    return false;
}
// Cmd0126, 现在故障解除
static void C485Cmd0126Resp(C485PkgHead* head)
{
    short code = ((short)head->data[3] << 8) | head->data[4];
    if(code == C485_FAULT_CODE_HIGH || code == C485_FAULT_CODE_LOW) { // TODO 本App目前仅支持取消高低温报警，其他故障解除因为spec没有相应处理逻辑，无法处理
        TgTemAlarmCancel(1);     // 协议规定：此指令重置高低温报警条件，客人要求，也要取消上电6小时/到达目标区间的前置条件
        c485_data_record.fault_code &= (~code);
        C485SendResponseByte(0x0126, 1, head->ordinal);
    }
    else
        C485SendResponseByte(0x0126, 0, head->ordinal);    // 无效的故障代码
}
// Cmd0127, 现在故障状态取得
static void C485Cmd0127Resp(C485PkgHead* head)
{
    short codes[7] = {0};
    int j = 0;
    sync_param_byte(zy_st.alarm, &c485_data_record.fault_code, NULL);     // 同步故障代码变更
    for(int i = 1; i <= C485_FAULT_CODE_DOOR; i = i << 1) {
        if(i & c485_data_record.fault_code) 
            codes[j++] = i;
    }
    if (j == 0) j = 1; // 没有错误也要返回0000
    C485SendResponseFewData(0x0127, codes, j, C485_DT_SHORT, head->ordinal);
}
// Cmd0127, 现在故障状态取得 - 主动
static bool C485Cmd0127(uint16_t value)
{
    short codes[7] = {0};
    int j = 0;
    for(int i = 1; i <= C485_FAULT_CODE_DOOR; i = i << 1) {
        if(i & value)
            codes[j++] = i;
    }
    if (j == 0) j = 1; // 没有错误也要返回0000
    return C485SendCmdFewData(0x0127, codes, 1, C485_DT_SHORT, 1);
}
// Cmd0128, 压缩机实时状态取得
static void C485Cmd0128Resp(C485PkgHead* head)
{
    uint8_t comp_status = (zy_st.comp_on_timer > 0) ? 0x01 : 0x00;  // 计算C485视角的压机状态: 0x01: 运行中, 0x00: 待机中
    sync_param_byte(comp_status, &c485_data_record.comp_status, NULL);     // 同步压机状态变更
    C485SendResponseByte(0x0128, c485_data_record.comp_status, 0);
}
// Cmd0128, 压缩机实时状态取得 - 主动
static bool C485Cmd0128(uint8_t value)
{
    return C485SendCmdByte(0x0128, value);
}
// Cmd0129, 门状态取得
static void C485Cmd0129Resp(C485PkgHead* head)
{
#if (ZQ_FUNC_DOOR1 == 1) 
    uint8_t door_state = (zy_st.door1_timer > 0) ? 0x01 : 0x00;    // 计算C485视角的门状态: 0x01: 开, 0x00: 关
    sync_param_byte(door_state, &c485_data_record.door_state, NULL);     // 同步门状态变更
    C485SendResponseByte(0x0129, c485_data_record.door_state, head->ordinal);
#else
    C485Cmd0102Resp(head);    // 不支持
#endif
}
// Cmd0129, 门状态取得 - 主动
static bool C485Cmd0129(uint8_t value)
{
    return C485SendCmdByte(0x0129, value);
}
// Cmd012A, 灯状态取得
static void C485Cmd012AResp(C485PkgHead* head)
{
    // sync_param_byte(light_status, &c485_data_record.light_state, NULL);     // 同步灯状态变更
    return C485Cmd0102Resp(head);    // 不支持
}
// Cmd012A, 灯状态取得 - 主动
static void C485Cmd012A(void)
{
    // 不支持
}
// Cmd012B, 功率值取得
static void C485Cmd012BResp(C485PkgHead* head)
{
    short values[3] = {zy_st.load_cur, zy_st.load_vol, zy_st.load_pow};
    C485SendResponseFewData(0x012B, values, 3, C485_DT_SHORT, head->ordinal);
}
// Cmd012B, 功率值取得 - 主动
static bool C485Cmd012B(void)
{
    short values[3] = {zy_st.load_cur, zy_st.load_vol, zy_st.load_pow};
    return C485SendCmdFewData(0x012B, values, 3, C485_DT_SHORT, 1);
}
// Cmd012C, 电池电压值取得
static void C485Cmd012CResp(C485PkgHead* head)
{
    if(IsWordValid(zy_st.vbat))
        C485SendResponseByte(0x012C, zy_st.vbat / 100, head->ordinal);
    else
        C485Cmd0102Resp(head);   // 不支持
}
// Cmd012D, 联网状态取得
static void C485Cmd012DResp(C485PkgHead* head)
{
    short net = ((short)head->data[3] << 8) | head->data[4];
    if((net & C485_NET_4G_DOING) == C485_NET_4G_DOING)
        zy_st._4g = MODE_4G_DIAL;
    else if((net & C485_NET_4G_DONE) == C485_NET_4G_DONE)
        zy_st._4g = MODE_4G_CONNECT;
    else if((net & C485_NET_4G_WEAK) == C485_NET_4G_WEAK || (net & C485_NET_SIM_NONE) == C485_NET_SIM_NONE || (net & C485_NET_SIM_FAULT) == C485_NET_SIM_FAULT || (net & C485_NET_SRV_ERROR) == C485_NET_SRV_ERROR)
        zy_st._4g = MODE_4G_NONE;
    if ((net & C485_NET_WIFI_DONE) == C485_NET_WIFI_DONE)
        zy_st.wifi = 1;
    else if ((net & C485_NET_WIFI_NONE) == C485_NET_WIFI_NONE)
        zy_st.wifi = 0;
    
    if(c485_not_response_timer == 0)     // 这个值大于0用于某些反向命令时，通知已经是上位机的回复，系统不需要再回复回复
        C485SendResponseShort(0x0103, head->cmd, head->ordinal); // 特别自动发送的回应
    else {
        // receive correct response, clear the track of c485_not_response_timer
        c485_not_response_timer = 0;     
        // receive correct response, clear retry data.
        if (C485_resend_len > C485_def_buf_len) free(C485_resend_buf); // 数据大于C485_def_buf_len, 使用客户分配的buf, 要释放
        C485_resend_buf = NULL;
    }

}
// Cmd012D, 联网状态取得 - 主动
static bool C485Cmd012D(void)
{
    c485_not_response_timer = 5000; // 主动请求，通知系统不需要再回复回复
    return C485SendCmdByte(0x012D, 0);
}
// Cmd012E, 冰柜蒸发风机状态设定
static void C485Cmd012EResp(C485PkgHead* head)
{
    return C485Cmd0102Resp(head);    // 不支持
}
// Cmd012E, 冰柜蒸发风机状态设定 - 主动
static void C485Cmd012E(void)
{
    // 不支持
}
// Cmd012F, 冰柜蒸发风机状态取得
static void C485Cmd012FResp(C485PkgHead* head)
{
    //sync_param_byte(fan_status, &c485_data_record.fan_status, NULL);     // 同步蒸发风机状态变更
    return C485Cmd0102Resp(head);    // 不支持
}
// Cmd012F, 冰柜蒸发风机状态取得 - 主动
static void C485Cmd012F(void)
{
    // 不支持
}
// Cmd0130, 灯状态设定
static void C485Cmd0130Resp(C485PkgHead* head)
{
    return C485Cmd0102Resp(head);    // 不支持
}
// Cmd0131, 灯电流取得
static void C485Cmd0131Resp(C485PkgHead* head)
{
    return C485Cmd0102Resp(head);    // 不支持
}
// Cmd0131, 灯电流取得
static void C485Cmd0131(void)
{
    // 不支持
}
// Cmd0132, 4G 信号值取得
static void C485Cmd0132Resp(C485PkgHead* head)
{
    zy_st._4g_strength = head->data[3];
    PmSetValue(pm_idx.f2, zy_st._4g_strength);
    if(c485_not_response_timer == 0)     // 这个值大于0用于某些反向命令时，通知已经是上位机的回复，系统不需要再回复回复
        C485SendResponseShort(0x0103, head->cmd, head->ordinal); // 特别自动发送的回应
    else {
        // receive correct response, clear the track of c485_not_response_timer
        c485_not_response_timer = 0;
        // receive correct response, clear retry data.
        if (C485_resend_len > C485_def_buf_len) free(C485_resend_buf); // 数据大于C485_def_buf_len, 使用客户分配的buf, 要释放
        C485_resend_buf = NULL;
    }
}
// Cmd0132, 4G 信号值取得 - 主动
static bool C485Cmd0132(void)
{
    c485_not_response_timer = 5000;  // 主动请求，通知系统不需要再回复回复
    return C485SendCmdByte(0x0132, 0);
}


// Cmd0201, 库制冷/制热模式设定
static void C485Cmd0201Resp(C485PkgHead* head)
{
    uint8_t pm = head->data[3];  // 0x01：常温；0x02：制冷；0x03：制热
    // TODO 这里暂时只处理常温/制冷, 协议逻辑似乎不正确，冷热切换对应ctrl_mode, 常温对应remote_switch, 组合会有问题, 
    if (pm != 1 && pm != 2)
        return C485Cmd0102Resp(head); // cmd not support
    zy_st.ctrl_switch = (pm == 2) ? (zy_st.ctrl_switch | CTRL_REMOTE_SWITCH) : (zy_st.ctrl_switch & ~CTRL_REMOTE_SWITCH);

    C485SendResponseByte(0x0201, 1, head->ordinal);
}
// Cmd0202, 库制冷/制热模式取得
static void C485Cmd0202Resp(C485PkgHead* head)
{
    // TODO 这里暂时只处理常温/制冷, 协议逻辑似乎不正确，冷热切换对应ctrl_mode, 常温对应remote_switch, 组合会有问题, 
    uint8_t ctrl_mode = 0x02; // (zy_st.ctrl_mode & CTRL_MODE_COOL) || (zy_st.ctrl_mode & CTRL_MODE_FREEZE)
    //if (zy_st.ctrl_mode & CTRL_MODE_HOT) ctrl_mode = 0x03; // zy_st.ctrl_mode & CTRL_MODE_HOT，TODO CTRL_MODE_ECO怎么处理？
    if (!(zy_st.ctrl_switch & CTRL_REMOTE_SWITCH)) ctrl_mode = 0x01;    // 常温/远程关机
    sync_param_byte(ctrl_mode, &c485_data_record.ctrl_mode, NULL);      // 控制器常温/制冷/制热状态 -- 变化
    C485SendResponseByte(0x0202, ctrl_mode, head->ordinal);
}
// TODO Cmd0202, 库制冷/制热模式取得 - 主动 -- 考虑到设置冷热模式会重启，所以可能没机会主动发这个cmd
static bool C485Cmd0202(uint8_t value)
{
    return C485SendCmdByte(0x0202, value);
}
// Cmd0203, 库设置温度设定
static void C485Cmd0203Resp(C485PkgHead* head) // TODO - 不考虑ECO模式影响
{
    short pm = ((short)(head->data[3]) - 100) * 10;  // -30~70℃, 0x64 = 100, 110 代表 10℃, 90 代表 - 10℃
    if(pm == pm_ctrl.ts)
        C485SendResponseByte(0x0203, head->data[3], head->ordinal);
    if (PmSetValue(pm_idx.ts, pm)) {
        PmSave();
        sync_param_short(pm_ctrl.ts, &c485_data_record.pm_ts, NULL);
        TgTemAlarmCancel(0); // 取消高低温报警
        C485SendResponseByte(0x0203, head->data[3], head->ordinal);
    }
    else
        return C485Cmd0102Resp(head); // 协议要求：当设定超出范围的数据时，冰柜机直接返回失败（无效指令）
}
// Cmd0204, 库设置温度取得
static void C485Cmd0204Resp(C485PkgHead* head) // TODO - 不考虑ECO模式影响
{
    sync_param_short(pm_ctrl.ts, &c485_data_record.pm_ts, NULL);
    C485SendResponseByte(0x0204, (uint8_t)(pm_ctrl.ts / 10 + 100), head->ordinal);
}
// Cmd0204, 库设置温度取得 - 主动
static bool C485Cmd0204(short value)
{
    return C485SendCmdByte(0x0204, (uint8_t)(value / 10 + 100));
}
// Cmd0205, 库高温报警温度设定
static void C485Cmd0205Resp(C485PkgHead* head)
{
    short pm = ((short)(head->data[3]) - 100) * 10;  // -99~99℃, 0x64 = 100, 110 代表 10℃, 90 代表 - 10℃
    if (pm == pm_ctrl.ah)
        C485SendResponseByte(0x0205, head->data[3], head->ordinal);
    if (PmSetValue(pm_idx.ah, pm)) {
        PmSave();
        sync_param_short(pm_ctrl.ah, &c485_data_record.pm_f5, NULL);
        TgTemAlarmCancel(0); // 取消高低温报警
        C485SendResponseByte(0x0205, head->data[3], head->ordinal);
    }
    else
        return C485Cmd0102Resp(head); // 根据库温设定原则推测协议要求：当设定超出范围的数据时，冰柜机直接返回失败（无效指令）
}
// Cmd0206, 库高温报警温度取得
static void C485Cmd0206Resp(C485PkgHead* head)
{
    sync_param_short(pm_ctrl.ah, &c485_data_record.pm_f5, NULL);
    C485SendResponseByte(0x0206, (uint8_t)(pm_ctrl.ah / 10 + 100), head->ordinal);
}
// Cmd0206, 库高温报警温度取得 - 主动
static bool C485Cmd0206(short value)
{
    return C485SendCmdByte(0x0206, (uint8_t)(value / 10 + 100));
}
// Cmd0207, 库低温报警温度设定
static void C485Cmd0207Resp(C485PkgHead* head)
{
    short pm = ((short)(head->data[3]) - 100) * 10;  // -99~99℃, 0x64 = 100, 110 代表 10℃, 90 代表 - 10℃
    if (pm == pm_ctrl.al)
        C485SendResponseByte(0x0206, head->data[3], head->ordinal);
    if (PmSetValue(pm_idx.al, pm)) {
        PmSave();
        sync_param_short(pm_ctrl.al, &c485_data_record.pm_f6, NULL);
        TgTemAlarmCancel(0); // 取消高低温报警
        C485SendResponseByte(0x0207, head->data[3], head->ordinal);
    }
    else
        return C485Cmd0102Resp(head); // 根据库温设定原则推测协议要求：当设定超出范围的数据时，冰柜机直接返回失败（无效指令）
}
// Cmd0208, 库高低报警温度取得
static void C485Cmd0208Resp(C485PkgHead* head)
{
    sync_param_short(pm_ctrl.al, &c485_data_record.pm_f6, NULL);
    C485SendResponseByte(0x0208, (uint8_t)(pm_ctrl.al / 10 + 100), head->ordinal);
}
// Cmd0208, 库高低报警温度取得 - 主动
static bool C485Cmd0208(short value)
{
    return C485SendCmdByte(0x0208, (uint8_t)(value / 10 + 100));
}
// Cmd0209, 库当前温度取得(显示温度)
static void C485Cmd0209Resp(C485PkgHead* head)
{
//#if ((ZQ_DISPLAY_PANEL_TYPE == DPT_INTEGRAL_3) || (ZQ_DISPLAY_PANEL_TYPE == DPT_INTEGRAL_0 || (ZQ_DISPLAY_PANEL_TYPE == DPT_INTEGRAL_4)))
//    if (zy_st.d_temp < 0) {
//    short tmp = (zy_st.d_temp >= 0) ? (zy_st.d_temp + 5) : (zy_st.d_temp - 5);      // 四舍五入
//    C485SendResponseByte(0x0209, (uint8_t)(tmp / 10 + 100), head->ordinal); 
//#else
//    C485SendResponseByte(0x0209, (uint8_t)(zy_st.d_temp / 10 + 100), head->ordinal); 
//#endif
    C485SendResponseByte(0x0209, (uint8_t)(zy_st.d_temp / 10 + 100), head->ordinal); //TODO 通讯协议和产品spec矛盾，目前客人要求暂时协议只保留整数，控制器支持小数
}
// Cmd020A, 库设置温度下限设定
static void C485Cmd020AResp(C485PkgHead* head)
{
    short pm = ((short)(head->data[3]) - 100) * 10;  // -99~99℃, 0x64 = 100, 110 代表 10℃, 90 代表 - 10℃
    //    return C485Cmd0102Resp(head); // 协议要求：当设定超出范围的数据时，冰柜机直接返回失败（无效指令）
    if (pm == pm_ctrl.r1)
        C485SendResponseByte(0x020A, head->data[3], head->ordinal);
    if (PmSetValue(pm_idx.r1, pm)) {
        PmSave();
        sync_param_short(pm_ctrl.r1, &c485_data_record.pm_r1, NULL);
        C485SendResponseByte(0x020A, head->data[3], head->ordinal);
    }
    else
        return C485Cmd0102Resp(head); // 协议要求：当设定超出范围的数据时，冰柜机直接返回失败（无效指令）
}
// Cmd020B, 库设置温度下限取得
static void C485Cmd020BResp(C485PkgHead* head)
{
    sync_param_short(pm_ctrl.r1, &c485_data_record.pm_r1, NULL);
    C485SendResponseByte(0x020B, (uint8_t)(pm_ctrl.r1 / 10 + 100), head->ordinal);
}
// Cmd020B, 库设置温度下限取得 - 主动
static bool C485Cmd020B(short value)
{
    return C485SendCmdByte(0x020B, (uint8_t)(value / 10 + 100));
}
// Cmd020C, 库设置温度上限设定
static void C485Cmd020CResp(C485PkgHead* head)
{
    short pm = ((short)(head->data[3]) - 100)*10;  // -99~99℃, 0x64 = 100, 110 代表 10℃, 90 代表 - 10℃
    //    return C485Cmd0102Resp(head); // 协议要求：当设定超出范围的数据时，冰柜机直接返回失败（无效指令）
    if (pm == pm_ctrl.r2)
        C485SendResponseByte(0x020C, head->data[3], head->ordinal);
    if (PmSetValue(pm_idx.r2, pm)) {
        PmSave();
        sync_param_short(pm_ctrl.r2, &c485_data_record.pm_r2, NULL);
        C485SendResponseByte(0x020C, head->data[3], head->ordinal);
    }
    else
        return C485Cmd0102Resp(head); // 协议要求：当设定超出范围的数据时，冰柜机直接返回失败（无效指令）
}
// Cmd020D, 库设置温度上限取得
static void C485Cmd020DResp(C485PkgHead* head)
{
    sync_param_short(pm_ctrl.r2, &c485_data_record.pm_r2, NULL);
    C485SendResponseByte(0x020D, (uint8_t)(pm_ctrl.r2 / 10 + 100), head->ordinal);
}
// Cmd020D, 库设置温度上限取得 - 主动
static bool C485Cmd020D(short value)
{
    C485SendCmdByte(0x020D, (uint8_t)(value / 10 + 100));
}
// Cmd020E, 库温度上回差取得
static void C485Cmd020EResp(C485PkgHead* head)
{
    sync_param_short(pm_ctrl.c1, &c485_data_record.pm_c1, NULL);
    C485SendResponseByte(0x020E, (uint8_t)(pm_ctrl.c1), head->ordinal);
}
// Cmd020E, 库温度上回差取得 - 主动
static void C485Cmd020E(short value)
{
    C485SendCmdByte(0x020E, (uint8_t)(value));
}
// Cmd020F, 库温度下回差取得
static void C485Cmd020FResp(C485PkgHead* head)
{
    sync_param_short(pm_ctrl.c2, &c485_data_record.pm_c2, NULL);
    C485SendResponseByte(0x020F, (uint8_t)(pm_ctrl.c2), head->ordinal);
}
// Cmd020F, 库温度下回差取得 - 主动
static bool C485Cmd020F(short value)
{
    return C485SendCmdByte(0x020F, (uint8_t)(value));
}
// Cmd0210, 库传感器故障压缩机开机时间取得
static void C485Cmd0210Resp(C485PkgHead* head)
{
    C485SendResponseByte(0x0210, (uint8_t)(pm_ctrl.c3), head->ordinal);
}
// Cmd0211, 库传感器故障压缩机关机时间取得
static void C485Cmd0211Resp(C485PkgHead* head)
{
    C485SendResponseByte(0x0211, (uint8_t)(pm_ctrl.c4), head->ordinal);
}
// Cmd0212, 库温度补偿值设定
static void C485Cmd0212Resp(C485PkgHead* head)
{
    short pm = (short)(head->data[3] - 100) * 10;  // -99~99℃, 0x64 = 100, 110 代表 10℃, 90 代表 - 10℃
    //TODO 通讯协议和产品spec矛盾，通讯协议只支持整数，但是目前所有产品SPEC是0.1度变化, 目前客人要求暂时协议支持整数，控制器支持小数
    if (pm == pm_ctrl.c5)
        C485SendResponseByte(0x0212, head->data[3], head->ordinal);
    if (PmSetValue(pm_idx.c5, pm)) {
        PmSave();
        sync_param_short(pm_ctrl.c5, &c485_data_record.pm_c5, NULL);
        C485SendResponseByte(0x0212, head->data[3], head->ordinal);
    }
    else
        return C485Cmd0102Resp(head); // 根据库温设定原则推测协议要求：当设定超出范围的数据时，冰柜机直接返回失败（无效指令）
}
// Cmd0213, 库温度补偿值取得
static void C485Cmd0213Resp(C485PkgHead* head)
{
    sync_param_short(pm_ctrl.c5, &c485_data_record.pm_c5, NULL);
    //TODO 通讯协议和产品spec矛盾，通讯协议只支持整数，但是目前所有产品SPEC是0.1度变化, 目前客人要求暂时协议支持整数，控制器支持小数
    C485SendResponseByte(0x0213, (uint8_t)(pm_ctrl.c5 / 10 + 100), head->ordinal);
}
// Cmd0213, 库温度补偿值取得 - 主动
static bool C485Cmd0213(short value)
{
    //TODO 通讯协议和产品spec矛盾，通讯协议只支持整数，但是目前所有产品SPEC是0.1度变化, 目前客人要求暂时协议支持整数，控制器支持小数
    return C485SendCmdByte(0x0213, (uint8_t)(value/10 + 100));
}
// Cmd0214, 库除霜周期/压缩机保护周期取得
static void C485Cmd0214Resp(C485PkgHead* head)
{
    if(pm_idx.c3 != ZQM_PM_IDX_NA)  // 支持主动加热化霜
        C485SendResponseByte(0x0214, (uint8_t)(pm_ctrl.d3), head->ordinal);
    else
        C485SendResponseByte(0x0214, (uint8_t)(pm_ctrl.d1), head->ordinal);
}
// Cmd0215, 库除霜时间/压缩机保护时间取得
static void C485Cmd0215Resp(C485PkgHead* head)
{
    if(pm_idx.c3 != ZQM_PM_IDX_NA)  // 支持主动加热化霜
        C485SendResponseByte(0x0215, (uint8_t)(pm_ctrl.d7), head->ordinal);
    else
        C485SendResponseByte(0x0215, (uint8_t)(pm_ctrl.d2), head->ordinal);
}
// Cmd0216, 库压缩机最小停机时间取得
static void C485Cmd0216Resp(C485PkgHead* head)
{
    C485SendResponseByte(0x0216, (uint8_t)(pm_ctrl.c7), head->ordinal);
}
// Cmd0217, 库环境温度取得
static void C485Cmd0217Resp(C485PkgHead* head)
{
    return C485Cmd0102Resp(head);
}
// Cmd0218, 库实际温度（温度传感器测量温度）取得
static void C485Cmd0218Resp(C485PkgHead* head)
{
    //short tmp = (zy_st.m_temp >= 0) ? (zy_st.m_temp + 5) : (zy_st.m_temp - 5);      // 四舍五入
    //C485SendResponseByte(0x0218, (uint8_t)(tmp / 10 + 100), head->ordinal);
    C485SendResponseByte(0x0218, (uint8_t)(zy_st.m_temp / 10 + 100), head->ordinal); //TODO 通讯协议和产品spec矛盾，目前客人要求暂时协议只保留整数，控制器支持小数
}
// Cmd0219, 库本地控制状态取得
static void C485Cmd0219Resp(C485PkgHead* head)
{
    C485SendResponseByte(0x0219, ((zy_st.ctrl_switch & CTRL_HARD_SWITCH) && (zy_st.ctrl_switch & CTRL_SOFT_SWITCH)) ? 2 : 1, head->ordinal);
    //return C485Cmd0102Resp(head);
}    
// Cmd0219, 库本地控制状态取得 - 主动
static void C485Cmd0219(C485PkgHead* head)
{
    C485SendCmdByte(0x0219, ((zy_st.ctrl_switch & CTRL_HARD_SWITCH) && (zy_st.ctrl_switch & CTRL_SOFT_SWITCH)) ? 2 : 1);
    //return 0;
}    


// Cmd0501, 开门次数清空
static void C485Cmd0501Resp(C485PkgHead* head)
{
#if (ZQ_FUNC_DOOR1 == 1) 
    zy_st.door1_count = 0;
    C485SendResponseByte(0x0501, 1, head->ordinal);  // 清除成功
#else
    C485Cmd0102Resp(head);    // 不支持
#endif
}
// Cmd0502, 开门次数取得
static void C485Cmd0502Resp(C485PkgHead* head)
{
#if (ZQ_FUNC_DOOR1 == 1) 
    C485SendResponseInt(0x0502, (int)zy_st.door1_count, head->ordinal);
#else
    C485Cmd0102Resp(head);    // 不支持
#endif
}
// Cmd0503, 客流次数清空
static void C485Cmd0503Resp(C485PkgHead* head)
{
#if (ZQ_FUNC_DOOR1 == 1) 
    zy_st.humman = 0;
    C485SendResponseByte(0x0503, 1, head->ordinal);  // 清除成功
#else
    return C485Cmd0102Resp(head);    // 不支持
#endif
}
// Cmd0504, 客流次数取得
static void C485Cmd0504Resp(C485PkgHead* head)
{
#if (ZQ_FUNC_DOOR1 == 1) 
    C485SendResponseInt(0x0504, (int)zy_st.humman, head->ordinal);
#else
    return C485Cmd0102Resp(head);    // 不支持
#endif
}

// 主要流程 -----------------------------------------------------------------------------------------------
static void C485DispatchCmd(C485PkgHead *head)
{
    if(head->ordinal > 1)   // this app only support 1 lib. 
        return C485Cmd0102Resp(head); // cmd not support

    switch(head->cmd >> 8) {     // 根据cmd的高位分块检索, 加快检索速度
        case 0x01:
            switch((uint8_t)head->cmd) {
                case 0x01:
                    return C485Cmd0101Resp(head);
                case 0x03:
                    return C485Cmd0103Resp(head);
                case 0x11:
                    return C485Cmd0111Resp(head);
                case 0x12:
                    return C485Cmd0112Resp(head);
                case 0x13:
                    return C485Cmd0113Resp(head);
                case 0x14:
                    return C485Cmd0114Resp(head);
                case 0x15:
                    return C485Cmd0115Resp(head);
                case 0x16:
                    return C485Cmd0116Resp(head);

                case 0x21:
                    return C485Cmd0121Resp(head);
                case 0x22:
                    return C485Cmd0122Resp(head);
                case 0x23:
                    return C485Cmd0123Resp(head);
                case 0x24:
                    return C485Cmd0124Resp(head);
                case 0x25:
                    return C485Cmd0125Resp(head);
                case 0x26:
                    return C485Cmd0126Resp(head);
                case 0x27:
                    return C485Cmd0127Resp(head);
                case 0x28:
                    return C485Cmd0128Resp(head);
                case 0x29:
                    return C485Cmd0129Resp(head);
                case 0x2A:
                    return C485Cmd012AResp(head);
                case 0x2B:
#if (ZQ_FUNC_POW_METER == 1) 
                    return C485Cmd012BResp(head);
#else
                    return C485Cmd0102Resp(head); // cmd not support
#endif
                case 0x2C:
                    return C485Cmd012CResp(head);
                case 0x2D:
                    return C485Cmd012DResp(head);
                case 0x2E:
                    return C485Cmd012EResp(head);
                case 0x2F:
                    return C485Cmd012FResp(head);
                case 0x30:
                    return C485Cmd0130Resp(head);
                case 0x31:
                    return C485Cmd0131Resp(head);
                case 0x32:
                    return C485Cmd0132Resp(head);
                default:
                    return C485Cmd0102Resp(head); // cmd not support
            }
            break;
        case 0x02:                          // 基本数据相关
            switch((uint8_t)head->cmd) {
                case 0x01:
                    return C485Cmd0201Resp(head);
                case 0x02:
                    return C485Cmd0202Resp(head);
                case 0x03:
                    return C485Cmd0203Resp(head);
                case 0x04:
                    return C485Cmd0204Resp(head);
                case 0x05:
                    return C485Cmd0205Resp(head);
                case 0x06:
                    return C485Cmd0206Resp(head);
                case 0x07:
                    return C485Cmd0207Resp(head);
                case 0x08:
                    return C485Cmd0208Resp(head);
                case 0x09:
                    return C485Cmd0209Resp(head);
                case 0x0A:
                    return C485Cmd020AResp(head);
                case 0x0B:
                    return C485Cmd020BResp(head);
                case 0x0C:
                    return C485Cmd020CResp(head);
                case 0x0D:
                    return C485Cmd020DResp(head);
                case 0x0E:
                    return C485Cmd020EResp(head);
                case 0x0F:
                    return C485Cmd020FResp(head);
                case 0x10:
                    return C485Cmd0210Resp(head);
                case 0x11:
                    return C485Cmd0211Resp(head);
                case 0x12:
                    return C485Cmd0212Resp(head);
                case 0x13:
                    return C485Cmd0213Resp(head);
                case 0x14:
                    return C485Cmd0214Resp(head);
                case 0x15:
                    return C485Cmd0215Resp(head);
                case 0x16:
                    return C485Cmd0216Resp(head);
                case 0x17:
                    return C485Cmd0217Resp(head);
                case 0x18:
                    return C485Cmd0218Resp(head);
                case 0x19:
                    return C485Cmd0219Resp(head);
                default:
                    return C485Cmd0102Resp(head); // cmd not support
            }
            break;
        case 0x05:                          // 统计数据相关
            switch((uint8_t)head->cmd) {
                case 0x01:
                    return C485Cmd0501Resp(head);
                case 0x02:
                    return C485Cmd0502Resp(head);
                case 0x03:
                    return C485Cmd0503Resp(head);
                case 0x04:
                    return C485Cmd0504Resp(head);
                default:
                    return C485Cmd0102Resp(head); // cmd not support
            }
            break;
        case 0x06:                          // 节能照明相关, 本APP不支持
        default:
            return C485Cmd0102Resp(head); // cmd not support
    }
    return;
}

void C485Updata(void)
{
    // 追踪运行状态变更 // 协议修改：不支持启动中和启动完成指令
    if (zq_timer_50ms == 0 && zq_timer_rtc_s_pow == 0)  // 计算C485视角的运行状态，50ms级上电初始化
        c485_run_state = C485_RUN_STATE_STARTING;       // 启动中
    else if (c485_run_state < C485_RUN_STATE_OTA)       // >=0x03的状态在其他(OTA)地方处理
        c485_run_state = C485_RUN_STATE_NORMAL;         // 启动中/启动完成(待机中), 等待0101指令同步
    //else  // 协议变更，不主动上报状态
    //    c485_run_state = c485_data_record.run_state; // 同步, 不更改状态        
    //if (sync_param_byte(c485_run_state, &c485_data_record.run_state, C485Cmd0125)) return;   // 控制器状态变更

    // 协议修改：启动后, 要等待智能模块先下发0101，才主动上报所有能主动上报的参数。远程切换模式/开关机等不需要等待
    if (c485_run_state != C485_RUN_STATE_CONNECTED) return;

    // TODO 这里暂时只处理常温/制冷, 协议逻辑似乎不正确，冷热切换对应ctrl_mode, 常温对应remote_switch, 组合会有问题, 
    uint8_t ctrl_mode = 0x02; // (zy_st.ctrl_mode & CTRL_MODE_COOL) || (zy_st.ctrl_mode & CTRL_MODE_FREEZE)
    //if (zy_st.ctrl_mode & CTRL_MODE_HOT) ctrl_mode = 0x03; // zy_st.ctrl_mode & CTRL_MODE_HOT，TODO CTRL_MODE_ECO怎么处理？
    if (!(zy_st.ctrl_switch & CTRL_REMOTE_SWITCH)) ctrl_mode = 0x01; // 常温/远程关机
    if (sync_param_byte(ctrl_mode, &c485_data_record.ctrl_mode, C485Cmd0202)) return;     // 控制器常温/制冷/制热状态 -- 变化

    if(sync_param_short((short)zy_st.alarm, &c485_data_record.fault_code, C485Cmd0127)) return;     // 故障代码变更
    uint8_t comp_status = (zy_st.comp_on_timer > 0) ? 0x01 : 0x00;  // 计算C485视角的压机状态: 0x01: 运行中, 0x00: 待机中
    if(sync_param_byte(comp_status, &c485_data_record.comp_status, C485Cmd0128)) return;     // 压机状态变更
    if (ZQ_FUNC_DOOR1 == 1) {
        uint8_t door_state = (zy_st.door1_timer > 0) ? 0x01 : 0x00;    // 计算C485视角的门状态: 0x01: 开, 0x00: 关
        if (sync_param_byte(door_state, &c485_data_record.door_state, C485Cmd0129)) return;     // 门状态变更
    }
    // if(sync_param_byte(light_status, &c485_data_record.light_state, C485Cmd012A)) return;     // 灯状态变更
    // if(sync_param_byte(fan_status, &c485_data_record.fan_status, C485Cmd012F)) return;     // 蒸发风机状态变更

    // 更新功率值/分钟
#if (ZQ_FUNC_POW_METER == 1)
    if (c485_data_record.pow_timer >= 60) {
        if (C485Cmd012B()) c485_data_record.pow_timer = 0;     // 发送功率值到上位机
        return;
    }
#endif

    // // 灯电流取得/分钟 - 不支持
    // if(c485_data_record.light_cur_timer >= 60) {
    //     if(C485Cmd0131()) c485_data_record.light_cur_timer = 0;     // 灯电流值到上位机
    //     return;
    // }
    // 冷热型
#if (ZQ_BOX_MODE == (CTRL_MODE_COOL | CTRL_MODE_HOT)) 
    if(sync_param_byte(ctrl_mode, &c485_data_record.ctrl_mode, C485Cmd0202)) return;     // 控制器制冷/制热状态 -- 变化会重启，应该走不到这里
#endif
    // 本地开关
#if (ZQ_FUNC_HARD_SWITCH == 1 || ZQ_FUNC_SOFT_SWITCH == 1)
    uint8_t local_switch = ((zy_st.ctrl_switch & CTRL_HARD_SWITCH) && (zy_st.ctrl_switch & CTRL_SOFT_SWITCH)) ? 2 : 1;     // 本地开关状态
    if (sync_param_byte(local_switch, &c485_data_record.local_switch, C485Cmd0219)) return;     // 本地开关状态变更
#endif
    // 追踪设置参数变更
    if(sync_param_short(pm_ctrl.ts, &c485_data_record.pm_ts, C485Cmd0204)) return;   // 设置温度变更 // TODO - 不考虑ECO模式影响
    if(sync_param_short(pm_ctrl.ah, &c485_data_record.pm_f5, C485Cmd0206)) return;   // 高温报警温度变更
    if(sync_param_short(pm_ctrl.al, &c485_data_record.pm_f6, C485Cmd0208)) return;   // 低温报警温度变更
    if(sync_param_short(pm_ctrl.r1, &c485_data_record.pm_r1, C485Cmd020B)) return;   // 设置温度下限变更  
    if(sync_param_short(pm_ctrl.r2, &c485_data_record.pm_r2, C485Cmd020D)) return;   // 设置温度上限变更
    if(sync_param_short(pm_ctrl.c1, &c485_data_record.pm_c1, C485Cmd020E)) return;   // 设置温度上回差变更
    if(sync_param_short(pm_ctrl.c2, &c485_data_record.pm_c2, C485Cmd020F)) return;   // 设置温度下回差变更
    if(sync_param_short(pm_ctrl.c5, &c485_data_record.pm_c5, C485Cmd0213)) return;   // 设置温度补偿值变更
    if (!IsByteValid(c485_data_record.net_flag)) {
        if (C485Cmd012D()) c485_data_record.net_flag = 1;     // 查询网络状态
        return;
    }
    if (!IsByteValid(c485_data_record._4g_strength_flag)) {
        if (C485Cmd0132()) c485_data_record._4g_strength_flag = 1;     // 查询信号强度
        return;
    }
}

void C485Task(void)
{
    // 1. 50ms级上电初始化
    if (zq_timer_50ms == 0 && zq_timer_rtc_s_pow == 0) {
        C485_resend_buf = NULL;
        UartInit(C485_UART_PORT, 115200, c485_rx_buf, C485_RX_BUF_SIZE, NULL);
        memset(&c485_data_record, 0x7f, sizeof(c485_data_record)); // 初始化一个奇怪的值，这样初始化第一次和系统值比较就都会不同，从而强迫上报
    }
    // 2. 追踪c485_not_response_timer
    if (c485_not_response_timer > 0) 
        c485_not_response_timer-=TASK_PERIOD;
    // 3. 每TASK_PERIOD轮询接收buffer, 处理上位机指令
    C485Recv(C485DispatchCmd);
    // 4. 每TASK_PERIOD轮询系统变更,发送主动指令
    if (C485_resend_buf == NULL) // 上次的主动指令发送已经完成, 指令buffer空
        C485Updata(); 
    else
        C485ResendData();       // send or resend active cmd
}
